﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Mighty.Common;
using System.Collections;

namespace Mighty.Brain
{
    public class NyBrain : BasicBrain
    {
        int getMighty = 0;
        int getJoker = 0;
        int cnt_spade = 0, cnt_clover = 0, cnt_diamond = 0, cnt_heart = 0;
        int[,] mycard = new int[4, 13];

        public override void GameStartEvent()
        {
            int i, j, k;

            for (j = 0, i = 0; j < 10; j++)//받은 카드들의 숫자와 모양을 확인해서 첫번째mycard배열에 따라 무늬를 분류하고 두번째 배열에 카드숫자를 저장한다.
            {
                if (gameInfo.myCards[j].shape == Shape.Clover)
                    for (k = 0; k < 13; k++)
                    {
                        if (gameInfo.myCards[j].number == k + 1)
                            mycard[i, k] = 1;
                    }

                if (gameInfo.myCards[j].shape == Shape.Diamond)
                    for (k = 0; k < 13; k++)
                    {
                        if (gameInfo.myCards[j].number == k + 1)
                            mycard[i + 1, k] = 1;
                    }

                if (gameInfo.myCards[j].shape == Shape.Heart)

                    for (k = 0; k < 13; k++)
                    {
                        if (gameInfo.myCards[j].number == k + 1)
                            mycard[i + 2, k] = 1;
                    }

                if (gameInfo.myCards[j].shape == Shape.Spade)

                    for (k = 0; k < 13; k++)
                    {
                        if (gameInfo.myCards[j].number == k + 1)
                            mycard[i + 3, k] = 1;
                    }
            }

            for (k = 0; k < 10; k++)///플래이어의 무늬에 따른 카드 수를 확인한다.
            {
                if (gameInfo.myCards[k].shape == Shape.Spade)

                    ++cnt_spade;

                if (gameInfo.myCards[k].shape == Shape.Clover)

                    ++cnt_clover;

                if (gameInfo.myCards[k].shape == Shape.Diamond)

                    ++cnt_diamond;

                if (gameInfo.myCards[k].shape == Shape.Heart)

                    ++cnt_heart;
            }

            for (k = 0; k < 10; k++)///플래이어가 마이티나 조커를 갖고 있는지 확인한다.
            {
                if (Shape.Diamond == gameInfo.myCards[k].shape)
                {
                    if (1 == gameInfo.myCards[k].number)
                        getMighty = 1;
                }

                if (Shape.Spade == gameInfo.myCards[k].shape)
                {
                    if (1 == gameInfo.myCards[k].number)
                        getMighty = 1;
                }

                if (Shape.Joker == gameInfo.myCards[k].shape)
                    getJoker = 1;
            }
        }
        public override Betting BettingTicEvent()
        {
            Betting betting = new Betting();
            Betting previousBetting = gameInfo.betting;

            betting.isPass = true;
             
            if (cnt_spade >= 4 || cnt_clover >= 4 || cnt_diamond >= 4 || cnt_heart >= 4)//각 무늬중에 같은무늬가 5개가 넘는 무늬가 있는지 확인한 후 같은무늬가 4개가 넘는 무늬중에 점수카드가 
                //4장이상이면 기존의 배팅보다 +1시켜서 배팅한다.
                {
                    if (mycard[0, 12] + mycard[0, 11] + mycard[0, 10] + mycard[0, 9] + mycard[0, 0] >= 2)
                    {
                        if (getMighty == 1 || getJoker == 1)//마이티카드와 조커카드가 있는지 확인한다.
                        {
                            if (previousBetting.limit == 0)//이전에 배팅이없었다면 14를 배팅한다.
                                betting.limit = 14;
                            else
                                betting.limit = previousBetting.limit + 1;//이전에 배팅이있었다면 배팅이 15미만일 경우 +1시켜서 배팅한다.
                            
                            betting.giruda = Giruda.Clover;
                            betting.isPass = false;
                        }
                    }

                    if (mycard[1, 12] + mycard[1, 11] + mycard[1, 10] + mycard[1, 9] + mycard[1, 0] >= 2)
                    {
                        if (getMighty == 1 || getJoker == 1)//마이티카드와 조커카드가 있는지 확인한다.
                        {
                            if (previousBetting.limit == 0)
                                betting.limit = 14;
                            else
                                betting.limit = previousBetting.limit + 1;

                            betting.giruda = Giruda.Diamond;
                            betting.isPass = false;
                        }
                    }

                    if (mycard[2, 12] + mycard[2, 11] + mycard[2, 10] + mycard[2, 9] + mycard[2, 0] >= 2)
                    {
                        if (getMighty == 1 || getJoker == 1)//마이티카드와 조커카드가 있는지 확인한다.
                        {
                            if (previousBetting.limit == 0)
                                betting.limit = 14;
                            else
                                betting.limit = previousBetting.limit + 1;

                            betting.giruda = Giruda.Heart;
                            betting.isPass = false;
                        }
                    }

                    if (mycard[3, 12] + mycard[3, 11] + mycard[3, 10] + mycard[3, 9] + mycard[3, 0] >= 2)
                    {
                        if (getMighty == 1 || getJoker == 1)//마이티카드와 조커카드가 있는지 확인한다.
                        {
                            if (previousBetting.limit == 0)
                                betting.limit = 14;
                            else
                                betting.limit = previousBetting.limit + 1;

                            betting.giruda = Giruda.Spade;
                            betting.isPass = false;
                        }
                    }
                }
            return betting;
        }

        /// <summary>
        /// 베팅완료, 주공이 정해졌다. 베팅이 끝났을 경우 처리할 코드가 있다면 여기에 하라.
        /// </summary>

        public override void BettingCompleteEvent()
        {

        }

        /// <summary>
        /// (주공)카드선택, 13장의 카드중 10장의 카드선택. 버릴3장의 카드에 cmdRemove=true로 설정해주어야 한다
        /// 만약 정확히 3장의 카드가 선택되지 않았을 경우에는 새로추가된 3장의 카드가 그대로 버려진다.
        /// ChoiceCardEvent 가 호출된 후에는 선택된 10장의 카드는 myCards[0]부터 차례대로 배치되고 버려진 3장의 카드는
        /// myCards[10]에서부터 배치되어 나중에 어떤 카드가 버려졌는지 알수 있게 해준다
        /// </summary>
        /// <remarks>
        /// [기본행동] 추가된 3장의 카드를 그대로 버린다
        /// </remarks>
        /// 기루다 무늬가 아닌 무늬의 10, j카드들을 우선으로 버린다. 그후 가장 카드 숫자가 적은 무늬의 카드들을 최대한으로 버린다.
        public override HandedCard[] ChoiceCardEvent()
        {
            int min;
            int temp_clover = cnt_clover, temp_diamond = cnt_diamond, temp_heart = cnt_heart, temp_spade = cnt_spade;
            int cnt = 0;
            int i;

            min = temp_clover;//카드수가 가장 적은 무늬를 선별해낸 후 min값에 대입한다.

            if (min > temp_diamond)
                min = temp_diamond;

            if (min > temp_heart)
                min = temp_heart;
 
            if (min > temp_spade)
                min = temp_spade;

            for ( i = 0; i <= 12; i++)//10,j카드들을 기루다 무늬가 아닐경우 버림패로 정한다.
            {
                if (gameInfo.myCards[i].number == 10 || gameInfo.myCards[i].number == 11)
                
                    if (gameInfo.myCards[i].shape != (Shape)gameInfo.betting.giruda)
                    {
                        gameInfo.myCards[i].cmdRemove = true;

                    cnt++;
                    }
                if (cnt == 3)
                    break;
            }

            ///각 무늬 중에 가장 적은 숫자가 있을 경우 

            if (cnt_clover == min)
            {
                for ( i = 0; i <= 12; i++)
                {
                    if (gameInfo.myCards[i].shape == Shape.Clover)

                        if(gameInfo.myCards[i].number != 13 || gameInfo.myCards[i].number != 14)

                        gameInfo.myCards[i].cmdRemove = true;

                        cnt++;

                        if (cnt == 3)
                            break;
                }
            }

            if (cnt_diamond == min)
            {
                for ( i = 0; i <= 12; i++)
                {
                    if (gameInfo.myCards[i].shape == Shape.Diamond)

                        if (gameInfo.myCards[i].number != 13 || gameInfo.myCards[i].number != 14)

                        gameInfo.myCards[i].cmdRemove = true;

                        cnt++;

                        if (cnt == 3)
                            break;
                }
            }

            if (cnt_heart == min)
            {
                for ( i = 0; i <= 12; i++)
                {
                    if (gameInfo.myCards[i].shape == Shape.Heart)

                        if (gameInfo.myCards[i].number != 13 || gameInfo.myCards[i].number != 14)

                        gameInfo.myCards[i].cmdRemove = true;

                        cnt++;

                        if (cnt == 3)
                            break;
                }
            }

            if (cnt_spade == min)
            {
                for ( i = 0; i <= 12; i++)
                {
                    if (gameInfo.myCards[i].shape == Shape.Spade)

                        if (gameInfo.myCards[i].number != 13 || gameInfo.myCards[i].number != 14)

                        gameInfo.myCards[i].cmdRemove = true;

                        cnt++;

                        if (cnt == 3)
                            break;
                }
            }
            return gameInfo.myCards;
        }

        /// <summary>
        /// 최종베팅정보, 기루다무늬변경가능. 기루다를 변경할 경우 최소+2된 limit정보를 리턴해야 한다
        /// </summary>
        /// <remarks>
        /// [기본행동] 아무런 변경도 하지 않는다
        /// </remarks>
        public override Betting LastBettingEvent()
        {
            return gameInfo.betting;
        }

        /// <summary>
        /// 주공의 최종베팅정보
        /// </summary>
        public override void LastBettingTalkEvent()
        {
        }

        /// <summary>
        /// (주공)프랜드선택. 프랜드를 선택하는 방법은 노프랜드(FriendPlayer.HowToSelect.nofriend),
        /// 초구프랜드(FriendPlayer.HowToSelect.firstwin),카드프랜드(FriendPlayer.HowToSelect.card)가 있다.
        /// </summary>
        /// <remarks>
        /// [기본행동] 초구프랜드를 선택한다
        /// </remarks>
        public override FriendPlayer ChoiceFriendEvent()
        {
            FriendPlayer f = new FriendPlayer();

            if (getMighty == 0)
            {
                f.howToSelect = FriendPlayer.HowToSelect.card;
                f.cardCondition = new Card(gameInfo.mighty.shape, gameInfo.mighty.number);
                return f;
            }

            else if (getJoker == 0)
            {
                f.howToSelect = FriendPlayer.HowToSelect.card;
                f.cardCondition = new Card(Shape.Joker, 14);
                return f;
            }

            else
            {
                f.howToSelect = FriendPlayer.HowToSelect.firstwin;
                return f;
            }
            
            //else if (getJoker == 0)
            //{
            //    f.howToSelect
            //}
        }

        /// <summary>
        /// 주공의 프랜드 정보
        /// </summary>
        public override void ChoiceFriendTalkEvent()
        {

        }

        /// <summary>
        /// 각라운드의시작
        ///  * 매라운드마다 초기화할 코드가 있다면 이부분에 들어가게 된다
        /// </summary>
        public override void RoundReadyEvent()
        {

        }

        /// <summary>
        /// 카드낼차례
        ///  * 각 사용자의 턴에 한번씩 호출되며 낼 카드를 결과값으로 리턴해야 한다. 
        ///  * 사용가능한 카드에는 myCards[i].isPossible 속성이 true로 설정되어 있다. 
        ///  * 만약 사용불가능한 카드를 낼 경우에 시스템은 카드배열에서 제일 처음 만나는 사용가능한 카드를 골라서 사용한다
        /// </summary>
        /// <remarks>
        /// [기본행동] 가능한 카드중에서 랜덤하게 하나의 카드를 선택한다
        /// </remarks>
        public override HandedCard RoundTicEvent()
        {
            /*ArrayList possibleCards = new ArrayList();
            foreach (HandedCard card in gameInfo.myCards)
            {
                if (card.isPossible) possibleCards.Add(card);
            }

            Random r = new Random();
            int k = r.Next(possibleCards.Count);

            return (HandedCard)possibleCards[k];

            //주공일 경우와 그렇지 않은 경우(1 : 프랜드인 경우, 2 : 프랜드가 아닌 경우)

            //주공일 경우는 기루다 무늬를 제외한 무늬중 가장 높은 숫자를 지닌 카드를 낸후, 기루다 플래이를 한다.

            //그렇지 않은 경우1은 그림카드 2장 이상이 나온 경우 조커나 마이티를 내고 그렇지 않은 경우는 기루다 플래이를 돕는다.

            //그렇지 않은 경우2는 기루다를 제외한 나머지 무늬중 가장 높은 숫자를 지닌 카드를 순서대로 낸다.

            HandedCard[] Collection = new HandedCard[10];

            if (gameInfo.attackPlayer.position == gameInfo.myInfo.position)
            {

            }

            else if (gameInfo.friend.position == gameInfo.myInfo.position)
            {

            }

            else
            {
            
            }*/
            if ((gameInfo.attackPlayer.name == gameInfo.myInfo.name && gameInfo.attackPlayer.position == gameInfo.myInfo.position) || (gameInfo.friend.name == gameInfo.myInfo.name && gameInfo.friend.position == gameInfo.myInfo.position))
            {
                HandedCard[] h = new HandedCard[10];

                int c = 0;

                for (int i = 0; i < 10; i++)
                    if (gameInfo.myCards[i].isPossible)
                        h[c++] = gameInfo.myCards[i];

                if (gameInfo.roundIdx == 0)
                {
                    for (int i = 0; i < c; i++)
                    {
                        if (h[i].number == 14 && h[i].shape != Shape.Joker && h[i].shape != gameInfo.mighty.shape)
                        {
                            return h[i];    // && (int) h[i].shape != (int) gameInfo.betting.giruda
                        }
                    }

                    return h[findMin(h, c)];
                }
                else if (gameInfo.roundIdx >= 1 && gameInfo.roundCardIdx == 0)
                {
                    HandedCard[] h2 = new HandedCard[10];

                    int c2 = 0;
                    for (int i = 0; i < c; i++)
                    {
                        if ((int)h[i].shape == (int)gameInfo.betting.giruda)
                        {
                            h2[c2++] = h[i];
                        }
                    }

                    if (c2 != 0)
                        return h2[findMax(h2, c2)];
                    else
                        return h[findMin(h, c)];
                }
            }

            HandedCard[] mine = new HandedCard[10];

            int cnt = 0;
            for (int i = 0; i < 10; i++)
                if (gameInfo.myCards[i].isPossible)
                    mine[cnt++] = gameInfo.myCards[i];

            int max = findMax(mine, cnt);
            int min = findMin(mine, cnt);

            if (gameInfo.roundCardIdx == 0)
                return (HandedCard)mine[min];

            if (pointcardCounter() > 0)
                if (canWin(mine, cnt))
                    if (gameInfo.roundIdx == 0 && mine[max].shape == Shape.Joker)
                        return (HandedCard)mine[(int)(min + max) / 2];
                    else
                        return (HandedCard)mine[max];

            if (gameInfo.roundIdx == 8)
                foreach (HandedCard h in mine)
                    if (h.shape == Shape.Joker)
                        return (HandedCard)h;

            //      if (mine[min].shape == Shape.Joker)
            //          return mine[(int) (min + max) / 2];

            return (HandedCard)mine[min];
        }

        /// <summary>
        /// 다른사람의 카드 정보
        /// </summary>
        public virtual void RoundCardThrowEvent()
        {
        }

        /// <summary>
        /// 각라운드의종료, 각 라운드가 종료되면 호출된다. 각 라운드의 승자는 gameinfo의 winner를 참조한다
        /// </summary>
        public virtual void RoundCompleteEvent()
        {
        
        }

        /// <summary>
        /// 게임의 종료, 게임이 종료되었을때 실행될 코드는 여기에 추가한다.
        /// </summary>
        public virtual void GameEndEvent()
        {
        
        }

        public int findMax(HandedCard[] card, int size)
        {
            int max = 0, index = 0;
            bool giruda = false, first = false;

            for(int i = 0; i < size; i++)
                if (card[i] == gameInfo.mighty)
                {
                    index = i;
                    break;
                }
                else if(card[i].shape == Shape.Joker)
                {
                    index = i;
                    max = 100 + 15;
                }
                else if (max < card[i].number && (int)gameInfo.betting.giruda == (int)card[i].shape)
                {
                    index = i;
                    max = card[i].number;
                    giruda = true;
                }
                else if (gameInfo.roundCardIdx != 0 && !giruda && max < card[i].number && gameInfo.roundHistory[gameInfo.roundIdx].cardStack[0].shape == card[i].shape)
                {
                    index = i;
                    max = card[i].number;
                    first = true;
                }
                else if (!giruda && !first && max < card[i].number)
                {
                    index = i;
                    max = card[i].number;
                }

            return index;
        }

        public int findMin(HandedCard[] card, int size)
        {
            int min = 16, index = 0;

            for (int i = 0; i < size; i++)
                if (min > card[i].number && card[i].number != 0)
                {
                    index = i;
                    min = card[i].number;
                }
            return index;
        }

        public int pointcardCounter()
        {
            int cnt = 0;
            for (int i = 0; i < gameInfo.roundCardIdx; i++)
                if (gameInfo.roundHistory[gameInfo.roundIdx].cardStack[i].number > 9)
                    cnt++;
            return cnt;
        }

        public bool canWin(HandedCard[] card, int size)
        {
            int max = findMax(card, size);
            for (int i = 0; i < gameInfo.roundCardIdx; i++)
            {
                HandedCard c = new HandedCard();
                c.shape = gameInfo.roundHistory[gameInfo.roundIdx].cardStack[i].shape;
                c.number = gameInfo.roundHistory[gameInfo.roundIdx].cardStack[i].number;
                if (win(c, card[max]))
                    return false;
            }
            return true;
        }

        public bool win(HandedCard a, HandedCard b)
        {
            if (a.shape == b.shape)
                if (a.number > b.number)
                    return true;
                else
                    return false;

            if (a.shape == gameInfo.mighty.shape && a.number == gameInfo.mighty.number)
                return true;
            else if (b.shape == gameInfo.mighty.shape && b.number == 14)
                return false;
            else if (a.shape == Shape.Joker && gameInfo.roundIdx != 0)
                return true;
            else if (b.shape == Shape.Joker && gameInfo.roundIdx != 0)
                return false;

            if ((int)a.shape == (int)gameInfo.betting.giruda)
                return true;
            else if ((int)b.shape == (int)gameInfo.betting.giruda)
                return false;
            else if (a.shape == gameInfo.roundHistory[gameInfo.roundIdx].cardStack[0].shape)
                return true;
            else if (a.shape == gameInfo.roundHistory[gameInfo.roundIdx].cardStack[0].shape)
                return false;
            else return false;
        }
    }
}